package ioc

import (
	"gitee.com/huanminabc/go-utils/common"
	"gitee.com/huanminabc/go-utils/reflect_extend"
	"reflect"
)

//自动识别函数和指针,并且自动注入
//如果函数的参数是非指针那么,会传递副本,如果是指针,那么会传递指针, 同理结构体也是一样
//如果函数参数是Lifecycle 那么就会自动绑定一个生命周期对象进去, 不区分指针和非指针都是可以的
//结构体中可以使用标记`inject:"not"` 来标记结构体字段不注入
//如果结构体字段全部都注入完毕后,那么将会从关联中删除,这样就会节约一些内存

func Bind(param interface{}) {
	if param == nil {
		panic("param is nil")
	}
	kind := reflect.TypeOf(param).Kind()
	switch kind {
	case reflect.Func:
		funInvoke(param)
	case reflect.Ptr: //如果是指针那么必须给指针初始化  var a= new(类型)  不然没办法给指针赋值,因为没有分配内存空间
		prtInvoke(param)
	default:
		panic("不支持的类型,只支持函数和指针")
	}

}

func BindInterface[T any](param interface{}, typeImpl T) {
	//获取指针的值
	value := reflect_extend.GetPtrType(param)
	name := reflect_extend.GetDefFullName(param)
	//判断是否是接口
	if value.Kind() == reflect.Interface {
		//找到这个接口的实现
		if v, ok := interfaceInjectMap[name]; ok {
			implName := reflect_extend.GetDefFullName(typeImpl)
			//找到这个接口的指定实现
			field := v.FindByField(func(element *InjectEntity) bool {
				return element.Name == implName
			})
			//因为本身就是实际值,所以直接赋值
			notPtr := reflect.ValueOf(field.Content).Interface()
			reflect_extend.SetPtrValue(param, notPtr)
			return
		} else {
			panic("没有找到" + name + "指针的注入")
		}
	} else {
		panic(name + "不是接口类型")
	}

}

func prtInvoke(ptr interface{}) {
	//获取指针的值
	value := reflect_extend.GetPtrType(ptr)
	name := reflect_extend.GetDefFullName(ptr)
	//将值给到指针
	if inject, ok := getInject(name); ok {
		//给指针赋值 , 因为是指针,所以需要取出指针内部的值,不然指针不能给指针赋值
		notPtr := reflect.ValueOf(inject.Content).Elem().Interface()
		reflect_extend.SetPtrValue(ptr, notPtr)
		return
	}
	//判断是否是接口
	if value.Kind() == reflect.Interface {
		//找到这个接口的实现
		if v, ok := interfaceInjectMap[name]; ok {
			//默认取第一个,本身就是指针,所以直接赋值
			first := v.First()
			//因为本身就是实际值,所以直接赋值
			notPtr := reflect.ValueOf(first.Content).Interface()
			reflect_extend.SetPtrValue(ptr, notPtr)
		}
		return
	}
	panic("没有找到" + name + "指针的注入")
}

func funInvoke(fun interface{}) {
	//获取函数参数
	args := reflect_extend.GetFuncInType(fun)
	var in []interface{}
	for _, arg := range args {
		var isPtr bool
		//判断如果是指针,那么取出指针内部的类型
		if arg.Kind() == reflect.Ptr {
			arg = arg.Elem()
			isPtr = true
		}
		path := getTypeFullPath(arg)
		//获取参数的类型
		if inject, ok := getInject(path); ok {
			//如果是指针,则返回指针
			if isPtr {
				in = append(in, inject.Content)
			} else {
				//取出指针内部的值
				ret := reflect_extend.GetPtrValue(inject.Content)
				//拷贝一份
				newValue := common.Copy(ret)
				in = append(in, newValue)
			}
		} else {

			//如果没有找到,则创建一个符合类型的指针或者值
			if isPtr {
				//判断是否是生命周期类型
				if arg == reflect.TypeOf(Lifecycle{}) {
					in = append(in, LifecycleGlobalPtr)
				} else {
					in = append(in, reflect.New(arg).Interface()) //创建一个新的指针
				}
			} else {
				//判断是否是生命周期类型
				if arg == reflect.TypeOf(Lifecycle{}) {
					in = append(in, LifecycleGlobal)
				} else {
					in = append(in, reflect.New(arg).Elem().Interface()) //取出指针内部的值
				}
			}
		}
	}
	values := reflect_extend.InterfacesToValue(in)
	//执行函数
	reflect.ValueOf(fun).Call(values)
}
